'use strict';

var assert = require('assert');
var md = require('../../lib/md');
var pkcs12 = require('../../lib/pkcs12');
var asn1 = require('../../lib/asn1');
var pki = require('../../lib/pki');

/**
 * Build a minimal certificate-only PKCS#12 (PFX) with a MAC.
 */
function buildCertOnlyPfxWithMac(password) {
  var keys = pki.rsa.generateKeyPair({bits: 1024, e: 0x10001});
  var cert = pki.createCertificate();
  cert.publicKey = keys.publicKey;
  cert.serialNumber = '01';
  cert.validity.notBefore = new Date();
  cert.validity.notAfter = new Date();
  cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1);
  cert.setSubject([{name: 'commonName', value: 'p12-demo'}]);
  cert.setIssuer([{name: 'commonName', value: 'p12-demo'}]);
  cert.sign(keys.privateKey, md.sha256.create());

  return pkcs12.toPkcs12Asn1(
    null,
    cert,
    password,
    {useMac: true, count: 2048, saltSize: 8}
  );
}

/**
 * Replace macData node with arbitrary junk.
 */
function corruptMacData(pfxAsn1) {
  var clone = asn1.fromDer(asn1.toDer(pfxAsn1).getBytes());
  // Replace 3rd element (macData) with garbage node
  clone.value[2] = asn1.create(
    asn1.Class.UNIVERSAL,
    asn1.Type.OCTETSTRING,
    false,
    'JUNK'
  );
  return clone;
}

describe('PKCS#12 MAC corruption', function() {
  var correctPw = 'correct-horse-battery-staple';
  var wrongPw = 'wrong-password';
  var legit;

  before(function() {
    legit = buildCertOnlyPfxWithMac(correctPw);
  });

  it('should accept valid PFX with correct password', function() {
    assert.doesNotThrow(function() {
      var obj = pkcs12.pkcs12FromAsn1(legit, true, correctPw);
      assert(obj, 'pkcs12FromAsn1 should return an object');
    });
  });

  it('should reject valid PFX with wrong password (MAC mismatch)', function() {
    assert.throws(function() {
      pkcs12.pkcs12FromAsn1(legit, true, wrongPw);
    }, /PKCS#12 MAC could not be verified. Invalid password?/);
  });

  it('should reject tampered PFX with corrupted macData', function() {
    var tampered = corruptMacData(legit);
    assert.throws(function() {
      pkcs12.pkcs12FromAsn1(tampered, true, wrongPw);
    }, /Invalid PKCS#12. macData field present but MAC was not validated./);
  });
});
